package com.zeyu.framework.tools.report.dynamic;

import com.google.common.collect.Lists;
import com.zeyu.framework.core.persistence.table.Field;
import com.zeyu.framework.tools.report.charts.ChartData;
import com.zeyu.framework.tools.report.charts.ExtendChartData;
import com.zeyu.framework.utils.Collections3;
import com.zeyu.framework.utils.StringUtils;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.reflect.MethodUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.awt.Color;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
 * 报表工具类
 * Created by zeyuphoenix on 16/9/4.
 */
public class ReportUtils {

    // ================================================================
    // Constants
    // ================================================================

    /**
     * logger
     */
    private static final Logger logger = LoggerFactory.getLogger(ReportUtils.class);

    /**
     * pdf转码后前缀
     */
    public static String BASE64_MARKER = ";base64,";

    // ================================================================
    // Fields
    // ================================================================

    // ================================================================
    // Constructors
    // ================================================================

    // ================================================================
    // Methods from/for super Interfaces or SuperClass
    // ================================================================

    // ================================================================
    // Public or Protected Methods
    // ================================================================

    /**
     * 根据chart data生成表格的head
     */
    public static Field[] generateColumnsFromChartData(ExtendChartData extendChartData) {
        // 表列
        Field[] columns = null;
        // 字符串组
        List<String> legends = extendChartData.getLegends();
        // 角度
        String angle = extendChartData.getAngle();
        if (StringUtils.isNotEmpty(angle)) {

            if (StringUtils.equalsIgnoreCase(extendChartData.getType(), "pie")) {
                columns = new Field[1 + 1];
            } else if (StringUtils.equalsIgnoreCase(extendChartData.getType(), "radar")) {
                columns = new Field[legends.size() + 2];
            } else if (StringUtils.equalsIgnoreCase(extendChartData.getType(), "gauge")) {
                columns = new Field[1 + 2];
            } else {
                columns = new Field[legends.size() + 1];
            }

            // 名称列
            columns[0] = new Field(angle, Field.FieldType.ANGLE);
            // render
            Field.Render render = null;
            if (StringUtils.equalsIgnoreCase("flow", extendChartData.getFormatType())) {
                render = new Field.Render("flowTransform");
            } else if (StringUtils.equalsIgnoreCase("package", extendChartData.getFormatType())) {
                render = new Field.Render("packetTransform");
            }

            if (StringUtils.equalsIgnoreCase(extendChartData.getType(), "pie")) {
                columns[1] = new Field(extendChartData.getName(), Field.FieldType.QUOTA);
                columns[1].setRender(render);
            } else if (StringUtils.equalsIgnoreCase(extendChartData.getType(), "radar")) {
                for (int i = 0; i < legends.size(); i++) {
                    columns[i + 1] = new Field(legends.get(i), Field.FieldType.QUOTA);
                    columns[i + 1].setRender(render);
                }
                columns[legends.size() + 1] = new Field("最大值", Field.FieldType.QUOTA);
                columns[legends.size() + 1].setRender(render);
            } else if (StringUtils.equalsIgnoreCase(extendChartData.getType(), "gauge")) {
                columns[1] = new Field(extendChartData.getName(), Field.FieldType.QUOTA);
                columns[1].setRender(render);
                columns[2] = new Field("最大值", Field.FieldType.QUOTA);
                columns[2].setRender(render);
            } else {
                for (int i = 0; i < legends.size(); i++) {
                    columns[i + 1] = new Field(legends.get(i), Field.FieldType.QUOTA);
                    columns[i + 1].setRender(render);
                }
            }
        }

        return columns;
    }

    /**
     * 根据chart data生成表格的数据,不进行数据格式转换
     */
    public static Object[][] generateDatasFromChartData(ExtendChartData extendChartData) {
        return generateDatasFromChartData(extendChartData, false);
    }


    /**
     * 根据chart data生成表格的数据
     */
    public static Object[][] generateDatasFromChartData(ExtendChartData extendChartData, boolean trans) {
        Object[][] datas = null;
        ChartData chartData = extendChartData.getDatas();
        if (chartData != null) {
            // basic data
            List<String> xAxis = chartData.getxAxis();
            List<List<Number>> series = chartData.getSeries();

            datas = new Object[xAxis.size()][];
            Object[] data;

            // render
            Field.Render render = null;
            if (trans) {
                // 因为表格已经转换了一次,所以这里可能不需要转换
                render = new Field.Render("packetTransform");
                if (StringUtils.equalsIgnoreCase("flow", extendChartData.getFormatType())) {
                    render = new Field.Render("flowTransform");
                } else if (StringUtils.equalsIgnoreCase("package", extendChartData.getFormatType())) {
                    render = new Field.Render("packetTransform");
                }
            }


            for (int i = 0; i < xAxis.size(); i++) {

                // 'line' 'bar' 'pie' ‘radar' 'gauge'
                if (StringUtils.equalsIgnoreCase(extendChartData.getType(), "radar")
                        || StringUtils.equalsIgnoreCase(extendChartData.getType(), "gauge")) {
                    data = new Object[2 + series.size()];
                    if (trans) {
                        data[1 + series.size()] = transform(render, chartData
                                .getMax().get(i));
                    } else {
                        data[1 + series.size()] = chartData
                                .getMax().get(i);
                    }
                } else {
                    data = new Object[1 + series.size()];
                }
                data[0] = xAxis.get(i);
                for (int k = 0; k < series.size(); k++) {
                    if (trans) {
                        data[k + 1] = transform(render, series.get(k).get(i));
                    } else {
                        data[k + 1] = series.get(k).get(i);
                    }
                }
                datas[i] = data;
            }
        }
        return datas;
    }

    /**
     * 转换流量、流量速率、存储、内存大小等以1024为换算的值
     */
    public static String flowTransform(Number val, int offset) {

        int fix = 2;
        if (offset > -1) {
            fix = offset;
        }

        if (val.longValue() == 0) {
            return val + "";
        }

        if (val.longValue() < 1024) {
            return val + " B";
        } else if (val.longValue() < 1048576) {
            return formatNumber(val.longValue() / 1024, fix) + " KB";
        } else if (val.longValue() < 1073741824) {
            return formatNumber(val.doubleValue() / 104857, fix) + " MB";
        } else {
            return formatNumber(val.doubleValue() / 1073741824, fix) + " GB";
        }
    }

    /**
     * 转换流量、流量速率、存储、内存大小等以1024为换算的值
     */
    public static String flowTransform(Number val) {
        return flowTransform(val, 2);
    }

    /**
     * 转换报文数、统计数、计算数等以1000为换算的值
     */
    public static String packetTransform(Number val, int offset) {

        int fix = 2;
        if (offset > -1) {
            fix = offset;
        }

        if (val.longValue() == 0) {
            return val + "";
        }
        if (val.longValue() < 1000) {
            return val + " ";
        } else if (val.longValue() < 1000000) {
            return formatNumber(val.doubleValue() / 1000, fix) + " K";
        } else if (val.longValue() < 1000000000) {
            return formatNumber(val.doubleValue() / 1000000, fix) + " M";
        } else {
            return formatNumber(val.doubleValue() / 1000000000, fix) + " G";
        }
    }

    /**
     * 转换报文数、统计数、计算数等以1000为换算的值
     */
    public static String packetTransform(Number val) {
        return packetTransform(val, 2);
    }

    /**
     * 截取指定位数
     */
    public static double formatNumber(double val, int offset) {
        BigDecimal bg = new BigDecimal(val);
        return bg.setScale(offset, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
     * 格式化 根据render
     */
    public static Object transform(Field.Render render, Object val) {
        if (render != null) {
            try {
                return MethodUtils.invokeStaticMethod(render.getCls(),
                        render.getMethodName(), new Object[]{val},
                        render.getParameterTypes());
            } catch (Exception e) {
                logger.error("",e);
            }
        }

        return val;
    }

    /**
     * 转换16进制字符串为颜色
     *
     * @param hex
     *            "#cccccc" or "cccccc" or "#cc" or "cc"
     */
    public static Color convert(String hex) {
        Color color = Color.gray;
        if (StringUtils.isNoneEmpty(hex)) {
            if (StringUtils.length(hex) == 2) {
                int v = Integer.valueOf(hex, 16);
                color = new Color(v, v, v);
            } else if (StringUtils.length(hex) == 3) {
                int v = Integer.valueOf(StringUtils.substring(hex, 1), 16);
                color = new Color(v, v, v);
            } else if (StringUtils.length(hex) == 6) {
                int v = Integer.valueOf(hex, 16);
                color = new Color(v);
            } else if (StringUtils.length(hex) == 7) {
                int v = Integer.valueOf(StringUtils.substring(hex, 1, 7), 16);
                color = new Color(v);
            }
        }

        return color;
    }

    /**
     * 将base64编码内容转换为Pdf
     * @param base64Content base64编码内容
     * @param filePath 文件的存储路径（含文件名）
     */
    public static void base64ToPdf(String base64Content, String filePath) {
        BufferedInputStream bis = null;
        FileOutputStream fos = null;
        BufferedOutputStream bos = null;

        try {
            byte[] bytes = Base64.decodeBase64(base64Content);//base64编码内容转换为字节数组
            ByteArrayInputStream byteInputStream = new ByteArrayInputStream(bytes);
            bis = new BufferedInputStream(byteInputStream);
            File file = new File(filePath);
            File path = file.getParentFile();
            if (!path.exists()) {
                boolean mk = path.mkdirs();
                logger.debug("file not exist mkdirs: ", mk);
            }
            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);

            byte[] buffer = new byte[1024];
            int length = bis.read(buffer);
            while (length != -1) {
                bos.write(buffer, 0, length);
                length = bis.read(buffer);
            }
            bos.flush();
        } catch (Exception e) {
            logger.error("string to pdf error: ", e);
        } finally {
            try {
                if (bis != null)
                    bis.close();
                if (fos != null)
                    fos.close();
                if (bos != null)
                    bos.close();
            } catch (IOException e) {
                logger.error("s2p close stream error: ", e);
            }
        }
    }

    /**
     * 将pdf文件转换为Base64编码
     * @param  file 要转的的pdf文件
     */
    public static String pdfToBase64(File file) {

        FileInputStream fin = null;
        BufferedInputStream bin = null;
        ByteArrayOutputStream baos;
        BufferedOutputStream bout = null;
        try {
            fin = new FileInputStream(file);
            bin = new BufferedInputStream(fin);
            baos = new ByteArrayOutputStream();
            bout = new BufferedOutputStream(baos);
            byte[] buffer = new byte[1024];
            int len = bin.read(buffer);
            while (len != -1) {
                bout.write(buffer, 0, len);
                len = bin.read(buffer);
            }
            //刷新此输出流并强制写出所有缓冲的输出字节
            bout.flush();
            byte[] bytes = baos.toByteArray();
            return Base64.encodeBase64String(bytes);

        } catch (IOException e) {
            logger.error("pdf to string error: ", e);
        } finally {
            try {
                if (fin != null)
                    fin.close();
                if (bin != null)
                    bin.close();
                if (bout != null)
                    bout.close();
            } catch (IOException e) {
                logger.error("p2s close stream error: ", e);
            }
        }
        return null;
    }

    /**
     * 根据时间间隔设置时间显示样式
     * 年 : 'yyyy-MM'
     * 月 : 'yyyy-MM-dd'
     * 周 : 'yyyy-MM-dd'
     * 日 : 'dd日HH:mm'
     */
    public static String patternByInterval(Date start, Date end) {

        return "dd日HH:mm";
    }


    /**
     * 根据索引添加空内容
     */
    public static void addSerie(List<List<Number>> series, int length) {
        if (Collections3.isEmpty(series) || series.size() != length) {
            for (int i = 0; i < length; i++) {
                series.add(Lists.newArrayList());
            }
        }
    }

    // ================================================================
    // Getter & Setter
    // ================================================================

    // ================================================================
    // Private Methods
    // ================================================================

    // ================================================================
    // Inner or Anonymous Class
    // ================================================================

    // ================================================================
    // Test Methods
    // ================================================================

}
